#include "IStream.h"
#include "Exceptions.h"
#include "Endian.h"

using namespace std;
using namespace boost;

namespace lhcutils
{

IStream::~IStream()
{
	;
}
	
int64_t IStream::Tell()
{
	return GetPosition();
}

void IStream::Seek(int64_t newPosition, SeekOrigin::Value origin)
{
	return SetPosition(newPosition, origin);
}

vector<uint8_t> IStream::ReadFull(size_t count)
{
	vector<uint8_t> buffer(count);
	size_t totalBytesRead = 0;
	size_t numBytesFromLastRead;

	while(totalBytesRead < count)
	{
		numBytesFromLastRead = Read(&(buffer[totalBytesRead]), count - totalBytesRead);
		if(numBytesFromLastRead == 0)
		{
			throw EndOfFileException(ustr("Read past the end of the stream."));
		}
		totalBytesRead += numBytesFromLastRead;
	}

	return buffer;
}

uint8_t IStream::ReadByte()
{
	vector<uint8_t> byte = ReadFull(1);
	return byte[0];
}

int32_t IStream::ReadInt32(Endianness::Value endianness)
{
	vector<uint8_t> bytes = ReadFull(4);
	int32_t value = *(reinterpret_cast<int32_t*>(&(bytes[0])));
	return ToHost32(value, endianness);
}

int32_t IStream::ReadInt32Le()
{
	return ReadInt32(Endianness::Little);
}

int32_t IStream::ReadInt32Be()
{
	return ReadInt32(Endianness::Big);
}

uint32_t IStream::ReadUint32(Endianness::Value endianness)
{
	vector<uint8_t> bytes = ReadFull(4);
	uint32_t value = *(reinterpret_cast<uint32_t*>(&(bytes[0])));
	return ToHost32(value, endianness);	
}

uint32_t IStream::ReadUint32Le()
{
	return ReadUint32(Endianness::Little);
}

uint32_t IStream::ReadUint32Be()
{
	return ReadUint32(Endianness::Big);
}

int64_t IStream::ReadInt64(Endianness::Value endianness)
{
	vector<uint8_t> bytes = ReadFull(8);
	int64_t value = *(reinterpret_cast<int64_t*>(&(bytes[0])));
	return ToHost64(value, endianness);
}

int64_t IStream::ReadInt64Le()
{
	return ReadInt64(Endianness::Little);
}

int64_t IStream::ReadInt64Be()
{
	return ReadInt64(Endianness::Big);
}

void IStream::Write(const std::vector<uint8_t>& buffer)
{
	if(buffer.size() > 0)
	{
		Write(&(buffer[0]), buffer.size());
	}
	else
	{
		Write(NULL, 0); // Maybe writing 0 bytes has some meaning.
	}
}

void IStream::WriteInt32(int32_t value, Endianness::Value endianness)
{
	int32_t converted = ToHost32(value, endianness);
	Write(&converted, 4);
}

void IStream::WriteInt32Le(int32_t value)
{
	WriteInt32(value, Endianness::Little);
}

void IStream::WriteInt32Be(int32_t value)
{
	WriteInt32(value, Endianness::Big);
}

void IStream::WriteInt64(int64_t value, Endianness::Value endianness)
{
	int64_t converted = ToHost64(value, endianness);
	Write(&converted, 8);
}

void IStream::WriteInt64Le(int64_t value)
{
	WriteInt64(value, Endianness::Little);
}

void IStream::WriteInt64Be(int64_t value)
{
	WriteInt64(value, Endianness::Big);
}

}

/*
 Copyright 2011 Greg Najda

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
